home *** CD-ROM | disk | FTP | other *** search
/ Magnum One / Magnum One (Mid-American Digital) (Disc Manufacturing).iso / d12 / cgazv5n4.arc / METAPHON.C < prev    next >
C/C++ Source or Header  |  1991-09-23  |  7KB  |  193 lines

  1. /*--- Listing 1 -------------------------- METAPHON.C -----------
  2. *
  3. * Author:  Gary A. Parker
  4. * Compilers: Turbo C++ 1.0, MSC 6.0
  5. * Memory model: any
  6. *
  7. * This is an implementation of the Metaphone algorithm developed
  8. * by Lawrence Phillips. like the Soundex algorithm, it compares 
  9. * words that sound alike but are spelled differently. Metaphone 
  10. * was designed to overcome difficulties encountered with Soundex
  11. *
  12. * Usage:
  13. * The calling function must pass three arguments:
  14. *
  15. *    char *Word      - the word to be converted to a 'metaph'
  16. *    char *Metaph    - a MAXMETAPH+1 byte field for the result
  17. *    int  Flag       - a flag
  18. *
  19. * If Flag is 1 then a 'metaph' will be computed for Word and
  20. * stored in Metaph.  If Flag is 0, then the function will compute
  21. * a 'metaph' for Word and compare it with the 'metaph', passed in
  22. * Metaph. It will return 0 for a match, else -1. The function 
  23. * will also return -1 if Word is 0 bytes long.
  24. *
  25. * This code is hereby placed in the public domain.
  26. *--------------------------------------------------------------*/
  27.  
  28. #include <ctype.h>
  29.  
  30. #define MAXMETAPH  4
  31.  
  32. int metaphone(char *, char *, int);
  33.  
  34. /* Character coding array */
  35. static char vsvfn[26] = {
  36.    1,16,4,16,9,2,4,16,9,2,0,2,2,2,1,4,0,2,4,4,1,0,0,0,8,0};
  37. /* A  B C  D E F G  H I J K L M N O P Q R S T U V W X Y Z*/
  38.  
  39. /* Macros to access character coding array */
  40. #define vowel(x)  (vsvfn[(x) - 'A'] & 1)  /* AEIOU */
  41. #define same(x)   (vsvfn[(x) - 'A'] & 2)  /* FJLMNR */
  42. #define varson(x) (vsvfn[(x) - 'A'] & 4)  /* CGPST */
  43. #define frontv(x) (vsvfn[(x) - 'A'] & 8)  /* EIY */
  44. #define noghf(x)  (vsvfn[(x) - 'A'] & 16) /* BDH */
  45.  
  46. int metaphone(char *Word, char *Metaph, int Flag)
  47. {
  48.     char *n, *n_start, *n_end; /* pointers to string */
  49.     char *metaph, *metaph_end; /* pointers to metaph */
  50.     char ntrans[32];           /* word with uppercase letters */
  51.     char newm[8];              /* new metaph for comparison */
  52.     int KSflag;                /* state flag for X translation */
  53.  
  54.     /*
  55.     ** Copy Word to internal buffer, dropping non-alphabetic
  56.     ** characters and converting to upper case.
  57.     */
  58.     for(n = ntrans + 1, n_end = ntrans + 30;
  59.         *Word && n < n_end; Word++)
  60.         if(isalpha(*Word)) *n++ = toupper(*Word);
  61.  
  62.     if(n == ntrans + 1) return -1; /* return if 0 bytes */
  63.     n_end = n;                /* set n_end to end of string */
  64.  
  65.     /* ntrans[0] will always be == 0 */
  66.     *n++ = 0; *n = 0; /* pad with nulls */
  67.     n = ntrans + 1;   /* assign pointer to start */
  68.  
  69.     /* if doing a comparison, redirect pointers */
  70.     if(!Flag) { metaph = Metaph; Metaph = newm; }
  71.  
  72.     /* check for PN KN GN AE WR WH and X at start */
  73.     switch(*n) {
  74.       case 'P': case 'K': case 'G':
  75.         if(*(n + 1) == 'N') *n++ = 0;
  76.         break;
  77.       case 'A': if(*(n + 1) == 'E') *n++ = 0;
  78.         break;
  79.       case 'W': if(*(n + 1) == 'R') *n++ = 0;
  80.         else if(*(n + 1) == 'H') {
  81.             *(n + 1) = *n;
  82.             *n++ = 0;
  83.         }
  84.         break;
  85.       case 'X': *n = 'S'; break;
  86.     }
  87.  
  88.     /*
  89.     ** Now, loop step through string, stopping at end of string
  90.     ** or when the computed 'metaph' is MAXMETAPH characters long
  91.     */
  92.     KSflag = 0; /* state flag for KS translation */
  93.     for(metaph_end = Metaph + MAXMETAPH, n_start = n;
  94.         n <= n_end && Metaph < metaph_end; n++) {
  95.  
  96.         if (KSflag) {
  97.             KSflag = 0;
  98.             *Metaph++ = *n;
  99.         }
  100.         else {
  101.             /* drop duplicates except for CC */
  102.             if(*(n - 1) == *n && *n != 'C') continue;
  103.  
  104.             /* check for F J L M N R or first letter vowel */
  105.             if(same(*n) || (n == n_start && vowel(*n)))
  106.                 *Metaph++ = *n;
  107.             else switch(*n) {
  108.               case 'B':
  109.                 if(n < n_end || *(n - 1) != 'M')
  110.                     *Metaph++ = *n;
  111.                 break;
  112.               case 'C':
  113.                 if(*(n - 1) != 'S' || !frontv(*(n + 1))) {
  114.                     if(*(n + 1) == 'I' && *(n + 2) == 'A')
  115.                         *Metaph++ = 'X';
  116.                     else if(frontv(*(n + 1))) *Metaph++ = 'S';
  117.                     else if(*(n + 1) == 'H')
  118.                         *Metaph++ = ((n == n_start &&
  119.                         !vowel(*(n + 2))) ||
  120.                         *(n -1) == 'S')
  121.                         ? (char)'K' : (char)'X';
  122.                     else *Metaph++ = 'K';
  123.                 }
  124.                 break;
  125.               case 'D':
  126.                 *Metaph++ = (*(n + 1) == 'G' && frontv(*(n + 2)))
  127.                     ? (char)'J' : (char)'T';
  128.                 break;
  129.               case 'G':
  130.                 if((*(n + 1) != 'H' || vowel(*(n + 2))) &&
  131.                     (*(n + 1) != 'N' || ((n + 1) < n_end &&
  132.                     (*(n + 2) != 'E' || *(n + 3) != 'D'))) &&
  133.                     (*(n - 1) != 'D' || !frontv(*(n + 1)) ) )
  134.                     *Metaph++ = (frontv(*(n  + 1)) &&
  135.                     *(n + 2) != 'G')
  136.                     ? (char)'J' : (char)'K';
  137.                 else if(*(n + 1) == 'H' && !noghf(*(n - 3))
  138.                     && *(n - 4) != 'H') *Metaph++ = 'F';
  139.                 break;
  140.               case 'H':
  141.                 if(!varson(*(n - 1)) && (!vowel(*(n - 1)) ||
  142.                     vowel(*(n + 1)))) *Metaph++ = 'H';
  143.                 break;
  144.               case 'K':
  145.                 if(*(n - 1) != 'C') *Metaph++ = 'K';
  146.                 break;
  147.               case 'P':
  148.                 *Metaph++ = *(n +  1) == 'H'
  149.                     ? (char)'F' : (char)'P';
  150.                 break;
  151.               case 'Q':
  152.                 *Metaph++ = 'K';
  153.                 break;
  154.               case 'S':
  155.                 *Metaph++ = (*(n + 1) == 'H' || (*(n  + 1) == 'I'
  156.                     && (*(n + 2) == 'O' || *(n + 2) == 'A')))
  157.                     ? (char)'X' : (char)'S';
  158.                 break;
  159.               case 'T':
  160.                 if(*(n  + 1) == 'I' && (*(n + 2) == 'O'
  161.                     || *(n + 2) == 'A') )
  162.                     *Metaph++ = 'X';
  163.                 else if(*(n + 1) == 'H') *Metaph++ = '0';
  164.                 else if(*(n + 1) != 'C' || *(n + 2) != 'H')
  165.                     *Metaph++ = 'T';
  166.                 break;
  167.               case 'V': *Metaph++ = 'F'; break;
  168.               case 'W': case  'Y':
  169.                 if(vowel(*(n + 1))) *Metaph++ = *n;
  170.                 break;
  171.               case 'X':
  172.                 if(n == n_start) *Metaph++ = 'S';
  173.                 else {
  174.                     *Metaph++ = 'K'; /* insert K, then S */
  175.                     KSflag = 1; /* this flag will cause S to be
  176.                             inserted on next pass thru loop */
  177.                 }
  178.                 break;
  179.               case 'Z': *Metaph++ = 'S'; break;
  180.             }
  181.         }
  182.  
  183.         /* compare new metaph with old */
  184.         if(!Flag && *(Metaph-1) != metaph[(Metaph - newm) - 1])
  185.             return -1;
  186.     }
  187.  
  188.     /* If comparing, check if metaphs were equal in length */
  189.     if(!Flag && metaph[Metaph - newm]) return -1;
  190.  
  191.     *Metaph = 0; /* null terminate return value */
  192.     return 0;
  193. }